// Package utils
// @Author: zhangdi
// @File: http_file
// @Version: 1.0.0
// @Date: 2023/6/28 17:29
package utils

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"os"
	"path/filepath"
	"time"
)

// UploadFile 上传文件函数
// 上传文件函数，参数为上传URL、文件字段名、文件路径和令牌
func UploadFile(uploadURL, fileFieldName, filePath, token string) error {
	// 打开文件
	file, err := os.Open(filePath)
	if err != nil {
		return fmt.Errorf("failed to open file: %v", err)
	}
	defer file.Close()

	// 创建一个存储请求体的缓冲区
	body := &bytes.Buffer{}
	// 创建一个多部分写入器
	writer := multipart.NewWriter(body)

	// 创建表单文件字段
	fileField, err := writer.CreateFormFile(fileFieldName, filePath)
	if err != nil {
		return fmt.Errorf("failed to create form file field: %v", err)
	}

	// 将文件数据拷贝到表单文件字段
	_, err = io.Copy(fileField, file)
	if err != nil {
		return fmt.Errorf("failed to copy file data to form file field: %v", err)
	}

	// 关闭写入器
	err = writer.Close()
	if err != nil {
		return fmt.Errorf("failed to close multipart writer: %v", err)
	}

	// 创建一个新的POST请求
	request, err := http.NewRequest("POST", uploadURL, body)
	if err != nil {
		return fmt.Errorf("failed to create request: %v", err)
	}

	// 设置请求头部信息
	request.Header.Set("Content-Type", writer.FormDataContentType())
	request.Header.Set("Authorization", "Bearer "+token)

	// 创建一个HTTP客户端并发送请求
	client := &http.Client{}
	response, err := client.Do(request)
	if err != nil {
		return fmt.Errorf("failed to send request: %v", err)
	}
	defer response.Body.Close()

	// 处理响应
	// ...

	return nil
}

// ParseResponseToFile 解析HTTP响应文件流到文件
func ParseResponseToFile(url, targetFilePath, token string) error {
	//targetDirectory := "/path/to/target/directory"

	// 创建HTTP客户端
	client := &http.Client{}

	// 发送请求
	req, err := http.NewRequest("GET", url, nil)
	req.Header.Set("Authorization", "Bearer "+token)
	req.Header.Set("ContentType", "application/json")

	if err != nil {
		return errors.New("Failed to create request:" + err.Error())
	}

	resp, err := client.Do(req)
	if err != nil {
		return errors.New("Failed to send request:" + err.Error())
	}
	defer resp.Body.Close()

	// 检查响应状态码
	if resp.StatusCode != http.StatusOK {
		return errors.New("Unexpected response:" + resp.Status)
	}

	//// 创建目标文件
	////filename := filepath.Join(targetDirectory, "downloaded_file.ext")
	//file, err := os.Create(targetFilePath)
	//if err != nil {
	//	return errors.New("Failed to create target file:" + err.Error())
	//}
	//defer file.Close()
	//
	//// 复制响应体到目标文件
	//_, err = io.Copy(file, resp.Body)
	//if err != nil {
	//	return errors.New("Failed to copy response body to file:" + err.Error())
	//}

	return copyResponseBodyToFile(resp.Body, targetFilePath)
}

// targetFilePath是否存在如果存在则直接resp.Body覆盖targetFilePath，否则则先创建
func copyResponseBodyToFile(respBody io.Reader, targetFilePath string) error {
	// 判断目标文件是否存在
	_, err := os.Stat(targetFilePath)
	if err == nil {
		// 目标文件存在，备份原文件到local_backup文件夹下
		err := backupTargetFile(targetFilePath)
		if err != nil {
			return err
		}
	} else if !os.IsNotExist(err) {
		// 判断目标文件存在错误
		return errors.New("Failed to check target file existence: " + err.Error())
	}

	// 目标文件不存在，创建新文件
	file, err := os.Create(targetFilePath)
	if err != nil {
		return errors.New("Failed to create target file: " + err.Error())
	}
	defer file.Close()

	// 复制响应体到目标文件
	_, err = io.Copy(file, respBody)
	if err != nil {
		return errors.New("Failed to copy response body to file: " + err.Error())
	}

	return nil
}

func backupTargetFile(targetFilePath string) error {
	// 获取目标文件所在的文件夹路径
	dirPath := filepath.Dir(targetFilePath)

	// 创建local_backup文件夹
	backupFolderPath := filepath.Join(dirPath, "local_backup")
	err := os.MkdirAll(backupFolderPath, 0755)
	if err != nil {
		return errors.New("Failed to create backup folder: " + err.Error())
	}

	// 生成备份文件名
	timestamp := time.Now().Format("2006-01-02_150405")
	backupFileName := "local_" + timestamp + ".db"

	// 备份原文件到local_backup文件夹下
	backupFilePath := filepath.Join(backupFolderPath, backupFileName)
	err = copyFile(targetFilePath, backupFilePath)
	if err != nil {
		return errors.New("Failed to backup target file: " + err.Error())
	}

	return nil
}

func copyFile(srcPath, destPath string) error {
	srcFile, err := os.Open(srcPath)
	if err != nil {
		return err
	}
	defer srcFile.Close()

	destFile, err := os.Create(destPath)
	if err != nil {
		return err
	}
	defer destFile.Close()

	_, err = io.Copy(destFile, srcFile)
	if err != nil {
		return err
	}

	return nil
}
